// deploy-cdn.js - 部署Vue应用到COS CDN的脚本
import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';

// 获取当前文件的目录路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 显示当前工作目录和脚本目录
console.log('当前工作目录:', process.cwd());
console.log('脚本目录:', __dirname);

// 命令行参数
const args = process.argv.slice(2);
const skipBuild = args.includes('--skip-build');

// 加载环境变量
dotenv.config();
console.log('环境变量加载成功');

// 从环境变量中读取COS配置
const cosConfig = {
  SecretId: process.env.COS_SECRET_ID,
  SecretKey: process.env.COS_SECRET_KEY,
  Bucket: process.env.COS_BUCKET || 'mybox-1257251314',
  Region: process.env.COS_REGION || 'ap-chengdu',
  Domain: process.env.COS_DOMAIN,
  cdnDomain: process.env.COS_CDN_DOMAIN || 'https://cos.roginx.ink',
  useAnonymous: process.env.COS_ANONYMOUS === 'true',
  // 各应用的部署路径
  Paths: {
    base: 'www/mico/vue/base',
    app1: 'www/mico/vue/app1',
    app2: 'www/mico/vue/app2'
  }
};

console.log('COS配置信息：', {
  Bucket: cosConfig.Bucket,
  Region: cosConfig.Region,
  cdnDomain: cosConfig.cdnDomain,
  SecretId: cosConfig.SecretId ? `${cosConfig.SecretId.substring(0, 5)}...` : '未设置',
  SecretKey: cosConfig.SecretKey ? '******' : '未设置'
});

// 检查是否安装了cos-nodejs-sdk-v5
let COS;
try {
  const cosModule = await import('cos-nodejs-sdk-v5');
  COS = cosModule.default || cosModule;
  console.log('COS SDK已加载');
} catch (e) {
  console.log('正在安装cos-nodejs-sdk-v5...');
  execSync('pnpm add cos-nodejs-sdk-v5 -D', { stdio: 'inherit' });
  const cosModule = await import('cos-nodejs-sdk-v5');
  COS = cosModule.default || cosModule;
  console.log('COS SDK安装并加载成功');
}

// 配置腾讯云COS
const cos = new COS({
  SecretId: cosConfig.SecretId,
  SecretKey: cosConfig.SecretKey
});

// 应用列表
const apps = [
  { name: 'vue-base', path: cosConfig.Paths.base },
  { name: 'vue-app1', path: cosConfig.Paths.app1 },
  { name: 'vue-app2', path: cosConfig.Paths.app2 }
];

/**
 * 构建指定的Vue应用
 * @param {string} appName 应用名称
 */
async function buildApp(appName) {
  if (skipBuild) {
    console.log(`跳过构建 ${appName}，使用已有的构建文件`);
    return true;
  }
  
  console.log(`开始构建 ${appName}...`);
  try {
    execSync(`pnpm --filter ${appName} build`, { stdio: 'inherit' });
    console.log(`${appName} 构建成功`);
    return true;
  } catch (error) {
    console.error(`${appName} 构建失败:`, error);
    return false;
  }
}

/**
 * 递归获取目录下的所有文件
 * @param {string} dir 目录路径
 * @returns {Array} 文件路径数组
 */
function getAllFiles(dir) {
  if (!fs.existsSync(dir)) {
    return [];
  }
  
  let results = [];
  const list = fs.readdirSync(dir);
  
  list.forEach(file => {
    const filePath = path.join(dir, file);
    const stat = fs.statSync(filePath);
    
    if (stat && stat.isDirectory()) {
      results = results.concat(getAllFiles(filePath));
    } else {
      results.push(filePath);
    }
  });
  
  return results;
}

/**
 * 获取文件的MIME类型
 * @param {string} filePath 文件路径
 * @returns {string} MIME类型
 */
function getMimeType(filePath) {
  const ext = path.extname(filePath).toLowerCase();
  const mimeTypes = {
    '.html': 'text/html',
    '.js': 'application/javascript',
    '.css': 'text/css',
    '.json': 'application/json',
    '.png': 'image/png',
    '.jpg': 'image/jpeg',
    '.jpeg': 'image/jpeg',
    '.gif': 'image/gif',
    '.svg': 'image/svg+xml',
    '.ico': 'image/x-icon',
    '.woff': 'font/woff',
    '.woff2': 'font/woff2',
    '.ttf': 'font/ttf',
    '.eot': 'application/vnd.ms-fontobject',
    '.otf': 'font/otf',
    '.txt': 'text/plain',
    '.map': 'application/json'
  };
  
  return mimeTypes[ext] || 'application/octet-stream';
}

/**
 * 上传单个文件到COS
 * @param {string} filePath 本地文件路径
 * @param {string} distDir 本地dist目录
 * @param {string} cosBaseDir COS目标目录
 * @returns {Promise} 上传结果Promise
 */
function uploadFile(filePath, distDir, cosBaseDir) {
  const relativePath = path.relative(distDir, filePath).replace(/\\/g, '/');
  const cosKey = cosBaseDir + '/' + relativePath;
  
  return new Promise((resolve, reject) => {
    cos.putObject({
      Bucket: cosConfig.Bucket,
      Region: cosConfig.Region,
      Key: cosKey,
      Body: fs.createReadStream(filePath),
      ContentType: getMimeType(filePath),
      Headers: {
        'x-cos-acl': 'public-read',
        'Access-Control-Allow-Origin': '*',
        'Cache-Control': relativePath.includes('index.html') ? 'no-cache' : 'max-age=31536000'
      }
    }, (err, data) => {
      if (err) {
        console.error(`上传失败: ${relativePath}`, err);
        reject(err);
        return;
      }
      console.log(`上传成功: ${relativePath} -> ${cosKey}`);
      resolve(data);
    });
  });
}

/**
 * 创建示例HTML文件
 * @param {string} appName 应用名称
 * @param {string} distDir 目标目录
 */
function createSampleHtml(appName, distDir) {
  if (!fs.existsSync(distDir)) {
    fs.mkdirSync(distDir, { recursive: true });
  }
  
  const htmlContent = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${appName} - 示例页面</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
      background-color: #f5f5f5;
    }
    .container {
      text-align: center;
      padding: 2rem;
      background-color: white;
      border-radius: 8px;
      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    }
    h1 {
      color: #3498db;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>${appName}</h1>
    <p>这是一个示例页面，用于测试部署流程。</p>
    <p>当前时间: ${new Date().toLocaleString()}</p>
  </div>
</body>
</html>
  `;
  
  fs.writeFileSync(path.join(distDir, 'index.html'), htmlContent);
  console.log(`已创建示例HTML文件: ${path.join(distDir, 'index.html')}`);
}

/**
 * 部署应用到COS
 * @param {string} appName 应用名称
 * @param {string} cosPath COS路径
 */
async function deployApp(appName, cosPath) {
  console.log(`开始部署 ${appName} 到 ${cosPath}...`);
  
  // 本地dist目录
  const distDir = path.resolve(__dirname, `apps/${appName}/dist`);
  
  // 检查dist目录是否存在，如果不存在则创建示例HTML
  if (!fs.existsSync(distDir) || fs.readdirSync(distDir).length === 0) {
    console.log(`警告: ${appName}/dist目录不存在或为空，创建示例HTML文件`);
    createSampleHtml(appName, distDir);
  }
  
  // 获取所有文件
  const files = getAllFiles(distDir);
  if (files.length === 0) {
    console.error(`错误: ${appName}/dist目录中没有文件可上传`);
    return false;
  }
  
  console.log(`找到 ${files.length} 个文件需要上传`);
  
  // 上传重要文件（HTML和入口JS）
  const importantFiles = files.filter(file => 
    file.includes('index.html') || 
    file.includes('main') ||
    file.includes('entry')
  );
  
  console.log(`首先上传 ${importantFiles.length} 个关键文件...`);
  for (const file of importantFiles) {
    await uploadFile(file, distDir, cosPath);
  }
  
  // 上传其他文件
  const otherFiles = files.filter(file => !importantFiles.includes(file));
  console.log(`上传剩余 ${otherFiles.length} 个文件...`);
  
  // 并行上传其他文件，每次10个
  const batchSize = 10;
  for (let i = 0; i < otherFiles.length; i += batchSize) {
    const batch = otherFiles.slice(i, i + batchSize);
    await Promise.all(batch.map(file => uploadFile(file, distDir, cosPath)));
    console.log(`进度: ${Math.min(i + batchSize, otherFiles.length)}/${otherFiles.length}`);
  }
  
  console.log(`${appName} 部署完成!`);
  console.log(`应用访问地址: ${cosConfig.cdnDomain}/${cosPath}/index.html`);
  
  return true;
}

/**
 * 主函数
 */
async function main() {
  try {
    console.log('开始构建和部署Vue项目到COS...');
    console.log(skipBuild ? '已启用跳过构建选项，将直接上传文件' : '将先构建项目再上传');
    
    // 构建和部署所有应用
    for (const app of apps) {
      console.log(`\n===== 处理应用: ${app.name} =====`);
      const buildSuccess = await buildApp(app.name);
      if (buildSuccess) {
        await deployApp(app.name, app.path);
      } else {
        console.error(`跳过 ${app.name} 的部署，因为构建失败`);
      }
    }
    
    console.log('\n所有Vue应用部署完成!');
    console.log(`基座应用: ${cosConfig.cdnDomain}/${cosConfig.Paths.base}/index.html`);
    console.log(`微应用1: ${cosConfig.cdnDomain}/${cosConfig.Paths.app1}/index.html`);
    console.log(`微应用2: ${cosConfig.cdnDomain}/${cosConfig.Paths.app2}/index.html`);
    
  } catch (error) {
    console.error('部署失败:', error);
    process.exit(1);
  }
}

// 执行主函数
main(); 